package com.hejun.jwt_security.config;

import com.alibaba.fastjson.JSON;
import com.hejun.jwt_security.filter.TokenFilter;
import com.hejun.jwt_security.vo.ResultVo;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityCustomizer;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.access.AccessDeniedHandler;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;

import java.io.IOException;
import java.io.PrintWriter;

@Configuration
public class SpringSecurityConfig {

//    @Autowired
//    MyAccessDeniedHandler myAccessDeniedHandler;
//    @Autowired
//    MyAuthenticationEntryPoint myAuthenticationEntryPoint;


    @Bean
    PasswordEncoder passwordEncoder(){
        return new BCryptPasswordEncoder();
    }

    @Bean
    UserDetailsService userDetailsService(){
        InMemoryUserDetailsManager manager= new InMemoryUserDetailsManager();

        //考虑到一般数据库存的是密文
        UserDetails user1= User.withUsername("admin").password(passwordEncoder().encode("123")).roles("admin").build();
        UserDetails user2= User.withUsername("boss").password(passwordEncoder().encode("123")).roles("boss").build();
        manager.createUser(user1);
        manager.createUser(user2);
        return manager;
    }
    //白名单
    @Bean
    WebSecurityCustomizer webSecurityCustomizer(){
        return web -> web.ignoring().requestMatchers("/login");
    }
    //配置过滤器链条   授权
    @Bean
    SecurityFilterChain filterChain(HttpSecurity security) throws Exception {

        security
                .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)//session策略设置成无状态——因为我们是前后分离项目，不用session存登录状态
                .and()
                .authorizeRequests()//如果你使用了authorizeHttpRequests，那么使用withObjectPostProcessor去配置我们自定义的元数据源和权限决策配置时是无效的，因为不会进去
                .requestMatchers("/admin").hasRole("admin")
                .requestMatchers("/boss").hasRole("boss")
                .anyRequest().authenticated()
                .and()
                //把自定义的过滤器加入到框架自带的UsernamePasswordAuthenticationFilter之前
                .addFilterBefore(new TokenFilter(userDetailsService()), UsernamePasswordAuthenticationFilter.class);

        //异常处理，拒绝访问
        security.exceptionHandling().accessDeniedHandler(new AccessDeniedHandler() {
            @Override
            public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException accessDeniedException) throws IOException, ServletException {
                response.setCharacterEncoding("UTF-8");
                PrintWriter out=response.getWriter();
                out.println(JSON.toJSONString(ResultVo.error(403,"权限不足")));
                out.flush();
                out.close();
            }
        });
        //异常处理，身份认证
        security.exceptionHandling().authenticationEntryPoint(new AuthenticationEntryPoint() {
            @Override
            public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException {
                response.setCharacterEncoding("UTF-8");
                PrintWriter out=response.getWriter();
                out.println(JSON.toJSONString(ResultVo.error(401,"身份认证不通过,请登录")));
                out.flush();
                out.close();
            }
        });
        return security.build();

    }
}